package com.wk.springframework.support;

import cn.hutool.core.bean.BeanUtil;
import com.wk.springframework.PropertyValue;
import com.wk.springframework.PropertyValues;
import com.wk.springframework.common.exception.BeanException;
import com.wk.springframework.config.BeanDefinition;
import com.wk.springframework.config.BeanReference;

import java.lang.reflect.Constructor;

/**
 * 很有能力的一个bean工厂哦
 */
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {

    private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();

    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) {
        Object obj;
        try {
//            obj = beanDefinition.getBeanClass().newInstance();
            obj = createBeanInstance(beanName, beanDefinition, args);
            applyPropertyValues(beanName,obj, beanDefinition );
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        addSingleton(beanName, obj);
        return obj;
    }

//    protected void applyPropertyValues(String beanName, BeanDefinition beanDefinition, Object bean) {
//        PropertyValues propertyValues = beanDefinition.getPropertyValues();
//        try {
//            if (propertyValues != null) {
//                for (PropertyValue propertyValue : propertyValues.getPropertyValueList()) {
//                    String propertyName = propertyValue.getName();
//                    Object propertyValueObj = propertyValue.getValue();
//                    if (propertyValueObj instanceof BeanReference) {
//                        BeanReference beanReference = (BeanReference) propertyValueObj;
//                        propertyValueObj = getBean(beanReference.getBeanName());
//                    }
//                    BeanUtil.setFieldValue(bean, propertyName, propertyValueObj);
//                }
//            }
//        } catch (Exception e) {
//            throw new BeanException("apply bean properties error beanName is " + beanName);
//        }
//    }

    protected void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
        try {
            PropertyValues propertyValues = beanDefinition.getPropertyValues();
            for (PropertyValue propertyValue : propertyValues.getPropertyValueList()) {

                String name = propertyValue.getName();
                Object value = propertyValue.getValue();

                if (value instanceof BeanReference) {
                    // A 依赖 B，获取 B 的实例化
                    BeanReference beanReference = (BeanReference) value;
                    value = getBean(beanReference.getBeanName());
                }
                // 属性填充
                BeanUtil.setFieldValue(bean, name, value);
            }
        } catch (Exception e) {
            throw new BeanException("Error setting property values：" + beanName);
        }
    }

    protected Object createBeanInstance(String beanName, BeanDefinition beanDefinition, Object[] args) {
        Class beanClass = beanDefinition.getBeanClass();
        Constructor targetCtor = null;
        try {
            Constructor[] declaredConstructor = beanClass.getDeclaredConstructors();
            for (Constructor constructor : declaredConstructor) {
                if (constructor != null && constructor.getParameterTypes().length == args.length) {
                    targetCtor = constructor;
                    break;
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return getInstantiationStrategy().instantiate(beanDefinition, beanName, targetCtor, args);
    }

    protected InstantiationStrategy getInstantiationStrategy() {
        return this.instantiationStrategy;
    }
}
